# @Version        : 1.0
# @Update Time    : 2025/8/16 21:31
# @File           : passport.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
from typing import Annotated

from fastapi import APIRouter, Request, Depends, Form
from fastapi.concurrency import run_in_threadpool
from fastapi.responses import RedirectResponse, StreamingResponse, ORJSONResponse, HTMLResponse

from applications.services.log_service import login_log
from applications.services.captcha_service import get_captcha
from applications.common.render_template import templates
from applications.common.user_manager import manager
from applications.utils.http import fail_api, ResultResponse
from applications.models import User
from applications.schemas.passport import LoginForm

route = APIRouter(prefix="/passport", tags=["系统模块-登录"])


# 获取验证码
@route.get(
    "/getCaptcha",
    summary="获取验证码",
    name="system.passport.captcha",
    response_class=StreamingResponse,
    include_in_schema=False,
)
async def captcha(request: Request):
    resp, code = await run_in_threadpool(get_captcha)
    request.session["code"] = code
    return StreamingResponse(content=resp, media_type="image/png")


# 登录
@route.get("/login", response_class=HTMLResponse, include_in_schema=False)
def login(request: Request, user: User = Depends(manager.optional)):
    if user:
        return RedirectResponse("/")
    return templates.TemplateResponse("system/login.html", {"request": request})


# 登录
@route.post("/login", summary="登录", response_model=ResultResponse)
async def login_post(request: Request, data: Annotated[LoginForm, Form()]):
    code = data.captcha

    s_code = request.session.get("code", None)
    request.session["code"] = None

    if not all([code, s_code]):
        await login_log(request, uid=None, form_data="{}", is_access=0, remark="验证码参数错误")
        return fail_api(msg="参数错误")

    if code != s_code:
        # 记录验证码错误（暂不明确用户是否存在）
        await login_log(
            request, uid=None, form_data=data.model_dump_json(exclude={"password"}), is_access=0, remark="验证码错误"
        )
        return fail_api(msg="验证码错误")

    user = await User.filter(username=data.username).first()

    if not user:
        # 用户不存在时记录（注意：此时无 user.id）
        await login_log(
            request, uid=None, form_data=data.model_dump_json(exclude={"password"}), is_access=0, remark="用户不存在"
        )
        return fail_api(msg="不存在的用户")

    if user.enable == 0:
        await login_log(
            request, uid=user.id, form_data=data.model_dump_json(exclude={"password"}), is_access=0, remark="用户被禁用"
        )
        return fail_api(msg="用户被暂停使用")

    if data.username == user.username and user.validate_password(data.password):
        # 登录成功
        token = manager.create_access_token(data=dict(sub=user.username))
        response = ORJSONResponse({"msg": "登录成功", "success": True})
        manager.set_cookie(response, token)

        # 记录成功日志（排除密码字段）
        await login_log(
            request, uid=user.id, form_data=data.model_dump_json(exclude={"password"}), is_access=1, remark="登录成功"
        )

        # 保存权限和角色到 session
        await user.fetch_related("roles")
        user_power = []
        user_roles = []
        for role in user.roles:
            if role.enable == 0:
                continue
            user_roles.append(role.code)
            await role.fetch_related("powers")
            for p in role.powers:
                if p.enable == 0:
                    continue
                user_power.append(p.code)
        request.session["permissions"] = user_power
        request.session["roles"] = user_roles

        return response

    # 密码错误
    await login_log(
        request, uid=user.id, form_data=data.model_dump_json(exclude={"password"}), is_access=0, remark="密码错误"
    )
    return fail_api(msg="用户名或密码错误")


# 退出登录
@route.post(
    "/logout",
    summary="退出登录",
    name="system.passport.logout",
    dependencies=[Depends(manager)],
)
def logout(request: Request):
    # 清除会话中的权限和角色信息
    if "permissions" in request.session:
        request.session.pop("permissions")
    if "roles" in request.session:
        request.session.pop("roles")

    # 创建响应并清除认证cookie
    response = ORJSONResponse(content={"success": True, "msg": "退出登录成功"})
    manager.set_cookie(response, "")

    return response
